package sf.database.dao;

import com.querydsl.core.types.Predicate;
import com.querydsl.sql.AbstractSQLQuery;
import com.querydsl.sql.AbstractSQLQueryFactory;
import com.querydsl.sql.Configuration;
import com.querydsl.sql.SQLQueryFactory;
import com.querydsl.sql.SQLTemplates;
import com.querydsl.sql.dml.SQLDeleteClause;
import com.querydsl.sql.dml.SQLInsertClause;
import com.querydsl.sql.dml.SQLMergeClause;
import com.querydsl.sql.dml.SQLUpdateClause;
import org.jooq.Condition;
import org.jooq.Delete;
import org.jooq.Insert;
import org.jooq.Record;
import org.jooq.SQLDialect;
import org.jooq.Select;
import org.jooq.Table;
import org.jooq.Update;
import sf.common.exception.SmallOrmException;
import sf.common.wrapper.Page;
import sf.core.DBCascadeField;
import sf.core.DBObject;
import sf.database.OrmConfig;
import sf.database.OrmContext;
import sf.database.datasource.SimpleRoutingDataSource;
import sf.database.dbinfo.DBMetaData;
import sf.database.dialect.DBDialect;
import sf.database.jdbc.sql.ConnectionCallback;
import sf.database.jdbc.sql.OrmIterator;
import sf.database.jdbc.sql.OrmStream;
import sf.database.jdbc.sql.ResultSetCallback;
import sf.database.mapper.DefaultMapperBuilder;
import sf.database.mapper.MapperBuilder;
import sf.database.meta.MetaHolder;
import sf.database.meta.OptimisticLock;
import sf.database.meta.TableMapping;
import sf.database.support.MetadataEventListener;
import sf.database.util.DBUtils;
import sf.dsl.Example;
import sf.ext.gen.GenConfig;
import sf.ext.gen.PojoGen;
import sf.spring.util.Assert;

import javax.inject.Provider;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * dbclient基础
 * 多数据源下需要使用多个DBClient,当前dbClient支持主从功能.
 * @author sxf
 */
public class DBClient extends DaoSupport implements DBMethod {

    protected MapperBuilder mapperBuilder = new DefaultMapperBuilder(this);

    /**
     * sql执行上下文.
     */
    protected ThreadLocal<DBContext> dbContexts = ThreadLocal.withInitial(() -> null);
    protected Map<DataSource, AbstractSQLQueryFactory> dataSourceSQLQueryFactoryMap = new ConcurrentHashMap<>(2);

    public DBClient(DataSource dataSource) {
        if (dataSource instanceof SimpleRoutingDataSource) {
            setDataSource((SimpleRoutingDataSource) dataSource);
        } else {
            SimpleRoutingDataSource routing = new SimpleRoutingDataSource("master", dataSource, null);
            setDataSource(routing);
        }
    }

    public DBClient() {

    }


    /**
     * 使用上下文语境(一次性的,每次使用后必须重新设置,供以后扩展使用.)
     * @param context 执行上下文.
     * @return
     */
    @Override
    public DBClient useContext(DBContext context) {
        Assert.notNull(context, "Context is null!");
        dbContexts.set(context);
        return this;
    }

    @Override
    protected DataSource getDataSource(boolean readonly) {
        DBContext context = dbContexts.get();
        if (context != null && context.getDataSource() != null) {
            return dataSource.getDataSource(context.getDataSource());
        }
        return super.getDataSource(readonly);
    }

    @Override
    protected Connection getConnection(DataSource ds) {
        DBContext context = dbContexts.get();
        if (context != null) {
            dbContexts.remove();
        }
        return getConnection(context, ds);
    }

    protected Connection getConnection(DBContext context, DataSource ds) {
        return super.getConnection(ds);
    }

    @Override
    protected void closeConnection(Connection conn, DataSource ds) {
        closeConnection(null, conn, ds);
    }

    protected void closeConnection(DBContext context, Connection conn, DataSource ds) {
        super.closeConnection(conn, ds);
    }

    @Override
    public <T extends DBObject> DBDialect getDialect(boolean readonly) {
        DataSource ds = getDataSource(readonly);
        Connection conn = getConnection(ds);
        try {
            DBDialect dialect = DBUtils.doGetDialect(conn, false);
            return dialect;
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> boolean existsByPrimaryKeys(Class<T> clz, Object... keyParams) {
        DataSource ds = getDataSource(true);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().existsByPrimaryKeys(conn, clz, keyParams);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> boolean exists(T query) {
        Assert.notNull(query, "");
        DataSource ds = getDataSource(true);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().exists(conn, query);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> T selectByPrimaryKeys(Class<T> clz, Object... keyParams) {
        DataSource ds = getDataSource(true);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().selectByPrimaryKeys(conn, clz, keyParams);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> long selectCount(T query) {
        DataSource ds = getDataSource(true);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            Long count = crud.getCrudModel().selectCount(conn, query);
            if (count == null) {
                count = 0L;
            }
            return count;
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> T selectOne(T query) {
        DataSource ds = getDataSource(true);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().selectOne(conn, query);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> T selectOneForUpdate(T query) {
        DataSource ds = getDataSource(false);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().selectOneForUpdate(conn, query);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> List<T> selectList(T query) {
        DataSource ds = getDataSource(true);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().selectList(conn, query);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> List<T> selectList(T query, long start, int limit) {
        DataSource ds = getDataSource(true);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().selectList(conn, query, start, limit);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> List<T> selectListForUpdate(T query) {
        DataSource ds = getDataSource(false);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().selectListForUpdate(conn, query);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> Page<T> selectPage(T query, long start, int limit) {
        DataSource ds = getDataSource(true);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().selectPage(conn, query, start, limit);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> Page<T> selectPage(Class<T> clz, OrmContext context, long start, int limit) {
        DataSource ds = getDataSource(true);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().selectPage(conn, start, limit, clz, context);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> T selectOne(Class<T> clz, OrmContext context) {
        DataSource ds = getDataSource(true);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().selectOne(conn, clz, context);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> List<T> selectList(Class<T> beanClass, OrmContext context) {
        DataSource ds = getDataSource(true);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().selectList(conn, beanClass, context);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> List<T> selectList(Class<T> beanClass, OrmContext context, long start, int limit) {
        DataSource ds = getDataSource(true);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().selectList(conn, beanClass, context, start, limit);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> void selectIterator(OrmIterator<T> ormIt, T query) {
        DataSource ds = getDataSource(true);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            crud.getCrudModel().selectIterator(conn, ormIt, query);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> void selectIterator(OrmIterator<T> ormIt, T query, long start, int limit) {
        DataSource ds = getDataSource(true);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            crud.getCrudModel().selectIterator(conn, ormIt, query, start, limit);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> void selectStream(OrmStream<T> ormStream, T query) {
        DataSource ds = getDataSource(true);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            crud.getCrudModel().selectStream(conn, ormStream, query);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> int insert(T obj) {
        DataSource ds = getDataSource(false);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().insert(conn, obj);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> int insertFast(T obj) {
        DataSource ds = getDataSource(false);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().insert(conn, obj, true, true);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> int insert(T obj, boolean fast, boolean useOptimisticLock) {
        DataSource ds = getDataSource(false);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().insert(conn, obj, fast, useOptimisticLock);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> int merge(T obj) {
        DataSource ds = getDataSource(false);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().merge(conn, obj);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> int update(T obj) {
        DataSource ds = getDataSource(false);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().update(conn, obj);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> int updateAndSet(T obj) {
        DataSource ds = getDataSource(false);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().updateAndSet(conn, obj);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> int updateWithVersion(T obj) {
        DataSource ds = getDataSource(false);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().updateWithVersion(conn, obj);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> void setNewOptimisticLockValues(T obj) {
        DataSource ds = getDataSource(false);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            OptimisticLock.setNewOptimisticLockValues(conn, obj);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> int deleteByPrimaryKeys(Class<T> clz, Object... keyParams) {
        DataSource ds = getDataSource(false);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().deleteByPrimaryKeys(conn, clz, keyParams);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> int delete(T obj) {
        DataSource ds = getDataSource(false);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().delete(conn, obj);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> void truncate(Class<T> clz) {
        DataSource ds = getDataSource(false);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            truncate(conn, MetaHolder.getMeta(clz));
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    /**
     * 执行 truncate table XXXX 命令，快速清光表的数据
     * @param meta 表名
     *             // route
     *             路由结果。该表对应的所有实例。
     */
    public int truncate(Connection con, TableMapping meta) {
        List<SQLException> errors = new ArrayList<SQLException>();
        int total = 0;
        try {
            DBMetaData.getInstance().truncate(con, meta, Collections.singletonList(meta.getTableName()));
        } catch (SQLException e) {
            errors.add(e);
        }
        return total;
    }

    @Override
    public int[] batchInsert(Collection<? extends DBObject> modelList) {
        return batchInsert(modelList, false);
    }

    @Override
    public int[] batchInsert(Collection<? extends DBObject> modelList, boolean useAll) {
        DataSource ds = getDataSource(false);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().batchInsert(conn, modelList, false, true, OrmConfig.getInstance().getBatchSize(), useAll);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public int[] batchInsertFast(Collection<? extends DBObject> modelList) {
        return batchInsertFast(modelList, false);
    }

    @Override
    public int[] batchInsertFast(Collection<? extends DBObject> modelList, boolean useAll) {
        DataSource ds = getDataSource(false);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().batchInsert(conn, modelList, true, true, OrmConfig.getInstance().getBatchSize(), useAll);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public int[] batchUpdate(Collection<? extends DBObject> modelList) {
        return batchUpdate(modelList, false);
    }

    @Override
    public int[] batchUpdate(Collection<? extends DBObject> modelList, boolean useNvl) {
        DataSource ds = getDataSource(false);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().batchUpdate(conn, modelList, OrmConfig.getInstance().getBatchSize(), useNvl);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public int[] batchDelete(Collection<? extends DBObject> modelList) {
        DataSource ds = getDataSource(false);
        Connection conn = null;
        try {
            conn = getConnection(ds);
            return crud.getCrudModel().batchDelete(conn, modelList, OrmConfig.getInstance().getBatchSize());
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }


    @Override
    public void genPojoCodes(String pkg, String srcPath, GenConfig config) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            PojoGen gen = new PojoGen(conn, pkg, srcPath, config);
            gen.gen();
        } catch (Exception e) {
            throw new SmallOrmException(e);
        } finally {
            closeConnection(conn, ds);
        }

    }

    /**
     * @param clz
     * @return
     */
    @Override
    public boolean createTable(Class<?> clz) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudModel().createTable(conn, clz);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }


    /**
     * 创建全部表
     * @return
     */
    @Override
    public boolean createTables() {
        boolean flag = false;
        Map<Class<?>, TableMapping> pool = MetaHolder.getAllClass();
        for (Map.Entry<?, TableMapping> entry : pool.entrySet()) {
            if (entry.getValue().getTableName() != null && DBObject.class.isAssignableFrom(entry.getValue().getThisType())) {
                DataSource ds = null;
                Connection conn = null;
                try {
                    ds = getDataSource(false);
                    conn = getConnection(ds);
                    crud.getCrudModel().createTable(conn, entry.getValue().getThisType());
                    flag = true;
                } catch (Exception e) {
                    throw new SmallOrmException(e);
                } finally {
                    closeConnection(conn, ds);
                }
            }
        }
        return flag;
    }

    @Override
    public boolean dropTable(Class<?> clz) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudModel().dropTable(conn, clz);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public boolean refreshTables() {
        boolean flag = false;
        Map<Class<?>, TableMapping> pool = MetaHolder.getAllClass();
        for (Map.Entry<?, TableMapping> entry : pool.entrySet()) {
            if (entry.getValue().getTableName() != null && DBObject.class.isAssignableFrom(entry.getValue().getThisType())) {
                DataSource ds = null;
                Connection conn = null;
                try {
                    ds = getDataSource(false);
                    conn = getConnection(ds);
                    DBMetaData.refreshTable(conn, entry.getValue().getThisType());
                    flag = true;
                } catch (Exception e) {
                    throw new SmallOrmException(e);
                } finally {
                    closeConnection(conn, ds);
                }
            }
        }
        return flag;
    }

    @Override
    public boolean refreshTable(Class<?> clz) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        boolean flag = false;
        try {
            DBMetaData.refreshTable(conn, clz);
            flag = true;
        } catch (Exception e) {
            throw new SmallOrmException(e);
        } finally {
            closeConnection(conn, ds);
        }
        return flag;
    }

    /**
     * 检查并修改数据库中的表，使其和传入的实体模型保持一致。
     * @param clz      要更新的表对应的类
     * @param listener 事件监听器，可以监听刷新过程的事件
     * @throws SQLException
     */
    @Override
    public void refreshTable(Class<?> clz, MetadataEventListener listener) throws SQLException {
        refreshTable(MetaHolder.getMeta(clz), listener, true, true);
    }

    /**
     * 检查并修改数据库中的表，使其和传入的实体模型保持一致。
     * @param meta             要更新的表的元数据
     * @param event            事件监听器，可以监听刷新过程的事件
     * @param modifyConstraint 更改约束
     * @param modifyIndexes    更改索引
     * @throws SQLException
     * @see MetadataEventListener
     */
    @Override
    public boolean refreshTable(TableMapping meta, MetadataEventListener event, boolean modifyConstraint, boolean modifyIndexes) throws SQLException {
        Assert.notNull(meta, "The table definition which your want to resresh must not null.");
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        boolean flag = false;
        try {
            DBMetaData.refreshTable(conn, meta, meta.getTableName(), event, modifyConstraint, modifyIndexes);
            flag = true;
        } catch (Exception e) {
            throw new SmallOrmException(e);
        } finally {
            closeConnection(conn, ds);
        }
        return flag;
    }

    @Override
    public <T extends DBObject> List<T> fetchCascade(T query, Class<T> clz, DBCascadeField... fields) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudModel().fetchCascade(conn, query, clz, fields);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> T fetchLinks(T obj) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudModel().fetchLinks(conn, obj);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> T fetchLinks(T obj, DBCascadeField... fields) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudModel().fetchLinks(conn, obj, fields);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public int execute(OrmContext context) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudModel().execute(conn, context);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public int insertCascade(DBObject obj, DBCascadeField... fields) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudModel().insertCascade(conn, obj, fields);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> T insertLinks(T obj, DBCascadeField... fields) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudModel().insertLinks(conn, obj, fields);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> T insertRelation(T obj, DBCascadeField... fields) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudModel().insertRelation(conn, obj, fields);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public int updateCascade(DBObject obj, DBCascadeField... fields) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudModel().updateCascade(conn, obj, fields);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> T updateLinks(T obj, DBCascadeField... fields) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudModel().updateLinks(conn, obj, fields);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> int updateRelation(T obj, DBCascadeField... fields) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudModel().updateRelation(conn, obj, fields);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> int deleteCascade(T obj, DBCascadeField... fields) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudModel().deleteCascade(conn, obj, fields);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> int deleteLinks(T obj, DBCascadeField... fields) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudModel().deleteLinks(conn, obj, fields);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends DBObject> int deleteRelation(T obj, DBCascadeField... fields) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudModel().deleteRelation(conn, obj, fields);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> Page<T> selectPage(long start, int limit, Class<T> beanClass, Example example) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudExample().selectPage(conn, start, limit, beanClass, example);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public Object[] selectArray(Example example) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudExample().selectArray(conn, example);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> List<T> selectList(Class<T> beanClass, Example example) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudExample().selectList(conn, beanClass, example);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> List<T> selectList(Class<T> beanClass, long start, int limit, Example example) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudExample().selectList(conn, beanClass, start, limit, example);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> List<T> selectListForUpdate(Class<T> beanClass, Example example) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudExample().selectListForUpdate(conn, beanClass, example);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> T selectOne(Class<T> beanClass, Example example) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudExample().selectOne(conn, beanClass, example);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> T selectOneForUpdate(Class<T> beanClass, Example example) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudExample().selectOneForUpdate(conn, beanClass, example);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public List<Map<String, Object>> select(Example example) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudExample().select(conn, example);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public List<Map<String, Object>> select(String sql, Object... paras) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudSql().select(conn, sql, paras);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> T selectOne(Class<T> beanClass, String sql, Object... parameters) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudSql().selectOne(conn, beanClass, sql, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> List<T> selectList(Class<T> beanClass, String sql, Object... parameters) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudSql().selectList(conn, beanClass, sql, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> List<T> selectList(Class<T> beanClass, long start, int limit, String sql, Object... parameters) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudSql().selectList(conn, beanClass, start, limit, sql, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public Object[] selectArray(String sql, Object... parameters) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudSql().selectArray(conn, sql, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> Page<T> selectPage(long start, int limit, Class<T> beanClass, String sql, Object... parameters) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudSql().selectPage(conn, start, limit, beanClass, sql, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> Page<T> selectRealPageRaw(long start, int limit, Class<T> beanClass, String countSql, Object[] countParas, String pageSql,
                                         Object[] pageParas) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudSql().selectRealPageRaw(conn, start, limit, beanClass, countSql, countParas, pageSql, pageParas);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> Page<T> selectFakePageRaw(long start, int limit, Class<T> beanClass, String countSql, Object[] countParas, String listSql, Object[] listParas) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudSql().selectFakePageRaw(conn, start, limit, beanClass, countSql, countParas, listSql, listParas);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> void selectIterator(OrmIterator<T> ormIt, Class<T> beanClass, String sql, Object... parameters) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            crud.getCrudSql().selectIterator(conn, ormIt, beanClass, false, sql, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> void selectIterator(OrmIterator<T> ormIt, Class<T> beanClass, boolean usePage, String sql, Object... parameters) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            crud.getCrudSql().selectIterator(conn, ormIt, beanClass, usePage, sql, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> void selectStream(OrmStream<T> ormStream, Class<T> beanClass, String sql, Object... parameters) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            crud.getCrudSql().selectStream(conn, ormStream, beanClass, false, sql, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> void selectStream(OrmStream<T> ormStream, Class<T> beanClass, boolean usePage, String sql, Object... parameters) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            crud.getCrudSql().selectStream(conn, ormStream, beanClass, usePage, sql, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> void selectResultSet(ResultSetCallback<T> callback, String sql, Object... parameters) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            crud.getCrudSql().selectResultSet(conn, callback, sql, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> T execute(ConnectionCallback<T> action) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudSql().execute(conn, action);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public int execute(String sql, Object... parameters) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudSql().execute(conn, sql, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public int[] executeBatch(String sql, List<Object[]> parameters) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudSql().executeBatch(conn, sql, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public int[] executeBatch(String sql, List<Object[]> parameters, boolean insertFast,
                              int batchSize, List<String> pkeys, List<Map<String, Object>> keyValues) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudSql().executeBatch(conn, sql, parameters, insertFast, batchSize, pkeys, keyValues);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }
////////////////////


    @Override
    public List<?> selectList(String resultSetMapping, String sql, Object... parameters) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudSql().selectList(conn, resultSetMapping, sql, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public List<?> selectList(String resultSetMapping, long start, int limit, String sql, Object... parameters) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudSql().selectList(conn, resultSetMapping, start, limit, sql, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public Object selectOne(String resultSetMapping, String sql, Object... parameters) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudSql().selectOne(conn, resultSetMapping, sql, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    ///////////////////// 模板id执行 //////////////////////
    @Override
    public List<Map<String, Object>> selectTemplate(String sqlId, Map<String, Object> parameter) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudTemplate().select(conn, sqlId, parameter);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> T selectOneTemplate(Class<T> beanClass, String sqlId, Map<String, Object> parameters) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudTemplate().selectOne(conn, beanClass, sqlId, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public Object[] selectArrayTemplate(String sqlId, Map<String, Object> parameters) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudTemplate().selectArray(conn, sqlId, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> Page<T> selectPageTemplate(long start, int limit, Class<T> beanClass, String sqlId,
                                          Map<String, Object> parameters) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudTemplate().selectPage(conn, start, limit, beanClass, sqlId, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> Page<T> selectRealPageRawTemplate(long start, int limit, Class<T> beanClass, String countSqlId, Map<String, Object> countParas, String pageSqlId, Map<String, Object> pageParas) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudTemplate().selectRealPageRaw(conn, start, limit, beanClass, countSqlId, countParas, pageSqlId, pageParas);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> Page<T> selectFakePageRawTemplate(long start, int limit, Class<T> beanClass, String countSqlId, Map<String, Object> countParas, String listSqlId, Map<String, Object> listParas) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudTemplate().selectFakePageRaw(conn, start, limit, beanClass, countSqlId, countParas, listSqlId, listParas);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> void selectIteratorTemplate(OrmIterator<T> ormIt, Class<T> beanClass, String sqlId, Map<String, Object> parameters) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            crud.getCrudTemplate().selectIterator(conn, ormIt, beanClass, sqlId, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> void selectStreamTemplate(OrmStream<T> ormStream, Class<T> beanClass, String sqlId, Map<String, Object> parameters) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            crud.getCrudTemplate().selectStream(conn, ormStream, beanClass, sqlId, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public int insertTemplate(String sqlId, Map<String, Object> paramters, List<String> pkeys, Map<String, Object> keyValues) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudTemplate().insert(conn, pkeys, keyValues, sqlId, paramters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public int executeTemplate(String sqlId, Map<String, Object> paramters) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudTemplate().execute(conn, sqlId, paramters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public int[] executeBatchTemplate(String sqlId, List<Map<String, Object>> parameters) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudTemplate().executeBatch(conn, sqlId, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public int[] executeBatchTemplate(String sqlId, List<Map<String, Object>> parameters, boolean insertFast,
                                      int batchSize, List<String> pkeys, List<Map<String, Object>> keyValues) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudTemplate().executeBatch(conn, sqlId, parameters, insertFast, batchSize, pkeys, keyValues);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> List<T> selectListTemplate(Class<T> beanClass, String sqlId, Map<String, Object> parameters) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudTemplate().selectList(conn, beanClass, sqlId, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    //模板source执行

    @Override
    public List<Map<String, Object>> selectTemplateSource(String sqlSource, Map<String, Object> parameter) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudTemplateSource().select(conn, sqlSource, parameter);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> T selectOneTemplateSource(Class<T> beanClass, String sqlSource, Map<String, Object> parameters) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudTemplateSource().selectOne(conn, beanClass, sqlSource, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public Object[] selectArrayTemplateSource(String sqlSource, Map<String, Object> parameters) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudTemplateSource().selectArray(conn, sqlSource, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> Page<T> selectPageTemplateSource(long start, int limit, Class<T> beanClass, String sqlSource,
                                                Map<String, Object> parameters) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudTemplateSource().selectPage(conn, start, limit, beanClass, sqlSource, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> Page<T> selectRealPageRawTemplateSource(long start, int limit, Class<T> beanClass, String countSqlSource, Map<String, Object> countParas, String pageSqlSource, Map<String, Object> pageParas) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudTemplateSource().selectRealPageRaw(conn, start, limit, beanClass, countSqlSource, countParas, pageSqlSource, pageParas);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> Page<T> selectFakePageRawTemplateSource(long start, int limit, Class<T> beanClass, String countSqlSource, Map<String, Object> countParas, String listSqlSource, Map<String, Object> listParas) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudTemplateSource().selectFakePageRaw(conn, start, limit, beanClass, countSqlSource, countParas, listSqlSource, listParas);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> void selectIteratorTemplateSource(OrmIterator<T> ormIt, Class<T> beanClass, String sqlSource, Map<String, Object> parameters) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            crud.getCrudTemplateSource().selectIterator(conn, ormIt, beanClass, sqlSource, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> void selectStreamTemplateSource(OrmStream<T> ormStream, Class<T> beanClass, String sqlSource, Map<String, Object> parameters) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            crud.getCrudTemplateSource().selectStream(conn, ormStream, beanClass, sqlSource, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public int insertTemplateSource(String sqlSource, Map<String, Object> paramters, List<String> pkeys, Map<String, Object> keyValues) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudTemplateSource().insert(conn, pkeys, keyValues, sqlSource, paramters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public int executeTemplateSource(String sqlSource, Map<String, Object> paramters) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudTemplateSource().execute(conn, sqlSource, paramters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public int[] executeBatchTemplateSource(String sqlSource, List<Map<String, Object>> parameters) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudTemplateSource().executeBatch(conn, sqlSource, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public int[] executeBatchTemplateSource(String sqlSource, List<Map<String, Object>> parameters, boolean insertFast,
                                            int batchSize, List<String> pkeys, List<Map<String, Object>> keyValues) {
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudTemplateSource().executeBatch(conn, sqlSource, parameters, insertFast, batchSize, pkeys, keyValues);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> List<T> selectListTemplateSource(Class<T> beanClass, String sqlSource, Map<String, Object> parameters) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudTemplateSource().selectList(conn, beanClass, sqlSource, parameters);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> List<T> selectListTemplateSource(Class<T> beanClass, long start, int limit, String sqlSource,
                                                Map<String, Object> parameters) {
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getCrudTemplateSource().selectList(conn, beanClass, sqlSource, parameters, start, limit);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    ///querydsl执行

    @Override
    public SQLTemplates queryDSLSQLTemplates(boolean readonly) {
        DataSource ds = getDataSource(readonly);
        Connection conn = getConnection(ds);
        try {
            return DBUtils.doGetDialect(conn, false).getQueryDslDialect();
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public Configuration queryDSLConfiguration(Class<? extends DBObject>... tableClass) {
        Class<? extends DBObject> one = null;
        if (tableClass != null && tableClass.length > 0) {
            one = tableClass[0];
        }
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getQueryDSLInf().queryDSLConfiguration(conn, tableClass);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public Provider<Connection> queryDSLProvider(boolean readonly) {
        throw new UnsupportedOperationException("not support!");
    }

    @Override
    public <T extends DBObject> boolean queryDSLExists(List<Predicate> predicates, Class<T> clz) {
        Assert.notNull(predicates, "返回类型不能为空");
//        Class<?> clz = QueryDSL.getQueryDSLTableClass(query);
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getQueryDSLInf().queryDSLExists(conn, predicates, clz);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> List<T> queryDSLSelectList(AbstractSQLQuery<?, ?> query, Class<T> returnClass) {
        Assert.notNull(returnClass, "返回类型不能为空");
//        Class<?> clz = QueryDSL.getQueryDSLTableClass(query);
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getQueryDSLInf().queryDSLSelectList(conn, query, returnClass);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> Page<T> queryDSLSelectPage(AbstractSQLQuery<?, ?> query, Class<T> returnClass, long start, int limit) {
        Assert.notNull(returnClass, "返回类型不能为空");
//        Class<?> clz = QueryDSL.getQueryDSLTableClass(query);
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getQueryDSLInf().queryDSLSelectPage(conn, query, returnClass, start, limit);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> T queryDSLSelectOne(AbstractSQLQuery<?, ?> query, Class<T> returnClass) {
        Assert.notNull(returnClass, "返回类型不能为空");
//        Class<?> clz = QueryDSL.getQueryDSLTableClass(query);
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getQueryDSLInf().queryDSLSelectOne(conn, query, returnClass);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> void queryDSLSelectIterator(OrmIterator<T> ormIt, Class<T> beanClass, AbstractSQLQuery<?, ?> query) {
        Assert.notNull(beanClass, "返回类型不能为空");
//        Class<?> clz = QueryDSL.getQueryDSLTableClass(query);
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            crud.getQueryDSLInf().selectIterator(conn, ormIt, query, beanClass);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> void queryDSLSelectStream(OrmStream<T> ormStream, Class<T> beanClass, AbstractSQLQuery<?, ?> query) {
        Assert.notNull(beanClass, "返回类型不能为空");
//        Class<?> clz = QueryDSL.getQueryDSLTableClass(query);
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            crud.getQueryDSLInf().selectStream(conn, ormStream, query, beanClass);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public int queryDSLInsert(SQLInsertClause insert) {
        Class<?> clz = null;
//        clz = QueryDSL.getInsertTableClass(insert);
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getQueryDSLInf().queryDSLInsert(conn, insert);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public int queryDSLInsert(SQLInsertClause insert, List<Map<String, Object>> keyValues) {
        Class<?> clz = null;
//        clz = QueryDSL.getInsertTableClass(insert);
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getQueryDSLInf().queryDSLInsert(conn, insert, keyValues);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public int queryDSLUpdate(SQLUpdateClause update) {
        Class<?> clz = null;
//        clz = QueryDSL.getUpdateTableClass(update);
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getQueryDSLInf().queryDSLUpdate(conn, update);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public int queryDSLDelete(SQLDeleteClause delete) {
        Class<?> clz = null;
//        clz = QueryDSL.getDeleteTableClass(delete);
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getQueryDSLInf().queryDSLDelete(conn, delete);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public int queryDSLMerge(SQLMergeClause merge) {
        Class<?> clz = null;
//        clz = QueryDSL.getMergeTableClass(merge);
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getQueryDSLInf().queryDSLMerge(conn, merge);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public int queryDSLMerge(SQLMergeClause merge, List<Map<String, Object>> keyValues) {
        Class<?> clz = null;
//        clz = QueryDSL.getMergeTableClass(merge);
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getQueryDSLInf().queryDSLMerge(conn, merge, keyValues);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public SQLQueryFactory sqlQueryFactory() {
        DataSource ds = getDataSource(true);
        SQLQueryFactory queryFactory = (SQLQueryFactory) dataSourceSQLQueryFactoryMap.get(ds);
        if (queryFactory == null) {
            queryFactory = createSQLQueryFactory(ds);
            dataSourceSQLQueryFactoryMap.put(ds, queryFactory);
        }
        return queryFactory;
    }

    protected SQLQueryFactory createSQLQueryFactory(DataSource ds) {
        Connection conn = getConnection(ds);
        SQLTemplates sqlTemplates = DBUtils.doGetDialect(conn, false).getQueryDslDialect();
        Configuration configuration = new Configuration(sqlTemplates);
        SQLQueryFactory queryFactory = new SQLQueryFactory(configuration, ds);
        return queryFactory;
    }

    ///////// jooq /////////// 支持

    @Override
    public <T extends DBObject> boolean jooqExists(SQLDialect sqlDialect, List<Condition> condition, Class<T> clz) {
        Assert.notNull(clz, "返回类型不能为空");
//        Class<?> clz = Jooq.getSelectFromTable(select);
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getJooqInf().jooqExists(conn, sqlDialect, condition, clz);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> T jooqSelectOne(Select<?> select, Class<T> returnClass) {
        Assert.notNull(returnClass, "返回类型不能为空");
//        Class<?> clz = Jooq.getSelectFromTable(select);
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getJooqInf().jooqSelectOne(conn, select, returnClass);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> List<T> jooqSelectList(Select<?> select, Class<T> returnClass) {
        Assert.notNull(returnClass, "返回类型不能为空");
//        Class<?> clz = Jooq.getSelectFromTable(select);
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getJooqInf().jooqSelectList(conn, select, returnClass);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> Page<T> jooqSelectPage(Select<?> countSelect, Select<?> pageSelect, Class<T> returnClass) {
        Assert.notNull(returnClass, "返回类型不能为空");
//        Class<?> clz = Jooq.getSelectFromTable(select);
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            return crud.getJooqInf().jooqSelectPage(conn, countSelect, pageSelect, returnClass);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> void jooqSelectIterator(OrmIterator<T> ormIt, Class<T> beanClass, Select<?> select) {
        Assert.notNull(beanClass, "返回类型不能为空");
//        Class<?> clz = Jooq.getSelectFromTable(select);
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            crud.getJooqInf().selectIterator(conn, ormIt, select, beanClass);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T> void jooqSelectStream(OrmStream<T> ormStream, Class<T> beanClass, Select<?> select) {
        Assert.notNull(beanClass, "返回类型不能为空");
//        Class<?> clz = Jooq.getSelectFromTable(select);
        DataSource ds = getDataSource(true);
        Connection conn = getConnection(ds);
        try {
            crud.getJooqInf().selectStream(conn, ormStream, select, beanClass);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends Record> int jooqInsert(Insert<T> insert) {
        Assert.notNull(insert, "");
        Class<?> clz = null;
//        Table<?> table = JooqVisitor.getInsertTable(insert);
//        if (table != null && table instanceof JooqTable) {
//            clz = ((JooqTable<?>) table).getClz();
//        }
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getJooqInf().jooqInsert(conn, insert);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends Record> int jooqInsert(Insert<T> insert, Table<T> table, Map<String, Object> keyValues) {
        Assert.notNull(insert, "");
        Class<?> clz = null;
//        Table<?> table = JooqVisitor.getInsertTable(insert);
//        if (table != null && table instanceof JooqTable) {
//            clz = ((JooqTable<?>) table).getClz();
//        }
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getJooqInf().jooqInsert(conn, insert, table, keyValues);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends Record> int jooqUpdate(Update<T> update) {
        Assert.notNull(update, "");
        Class<?> clz = null;
//        Table<?> table = JooqVisitor.getUpdateTable(update);
//        if (table != null && table instanceof JooqTable) {
//            clz = ((JooqTable<?>) table).getClz();
//        }
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getJooqInf().jooqUpdate(conn, update);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    @Override
    public <T extends Record> int jooqDelect(Delete<T> delete) {
        Assert.notNull(delete, "");
        Class<?> clz = null;
//        Table<?> table = JooqVisitor.getDeleteTable(delete);
//        if (table != null && table instanceof JooqTable) {
//            clz = ((JooqTable<?>) table).getClz();
//        }
        DataSource ds = getDataSource(false);
        Connection conn = getConnection(ds);
        try {
            return crud.getJooqInf().jooqDelect(conn, delete);
        } catch (RuntimeException e) {
            throw e;
        } finally {
            closeConnection(conn, ds);
        }
    }

    //////////////////// 代理接口///////////////////

    /**
     * 通过mapper接口生成dao代理
     * @param mapperInterface
     * @return
     */
    @Override
    public <T> T getMapper(Class<T> mapperInterface) {
        return this.mapperBuilder.getMapper(mapperInterface);
    }
}
